package h5cache

import (
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/labstack/echo"
)

// html5 缓存
type Cache struct {
	sync.RWMutex
	etag     string
	manifest []string
}

// 创建一个缓存实例
func New() *Cache {
	return &Cache{
		etag:     fmt.Sprintf("%v", time.Now().UnixNano()),
		manifest: []string{},
	}
}

// 注册静态文件
func (hc *Cache) Static(path string) {
	err := filepath.Walk(path, func(p string, f os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if f.IsDir() {
			return nil
		}

		p, _ = filepath.Rel(path, p)
		hc.manifest = append(hc.manifest, filepath.ToSlash(filepath.Join("/", p)))
		return nil
	})
	if err != nil {
		panic(err)
	}
}

// 注册一个缓存
func (hc *Cache) Register(path string) {
	hc.manifest = append(hc.manifest, path)
}

// 更新缓存
func (hc *Cache) Update() echo.MiddlewareFunc {
	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			hc.Lock()
			hc.etag = fmt.Sprintf("%v", time.Now().UnixNano())
			hc.Unlock()
			return next(c)
		}
	}
}

// 返回一个manifest handler
func (hc *Cache) Manifest() echo.HandlerFunc {
	return func(c echo.Context) error {
		hc.RLock()
		etag := hc.etag
		hc.RUnlock()

		if etag == c.Request().Header().Get("If-None-Match") {
			return c.NoContent(http.StatusNotModified)
		}

		response := c.Response()
		header := response.Header()
		header.Set("ETag", etag)
		header.Set(echo.HeaderContentType, "text/cache-manifest; charset=UTF-8")

		_, err := response.Write([]byte(fmt.Sprintf("CACHE MANIFEST\n# %v\n%v\nNETWORK:\n*\n", etag, strings.Join(hc.manifest, "\n"))))
		return err
	}
}
